﻿using System.Diagnostics;
using Antares.Converters;
using AntaresShell.Common;
using Repository.MODELs;
using Repository.Repositories;
using Repository.Sync;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using Windows.Devices.Input;
using Windows.System;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media.Animation;
using Windows.UI.Xaml.Media.Imaging;

// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234238

namespace Antares.VIEWs
{
    /// <summary>
    /// An empty page that can be used on its own or navigated to within a Frame.
    /// </summary>
    public sealed partial class TimelineDayPage
    {
        private const int IMAGE_WIDTH = 2850;
        private const double EPSILON = 1e-9;
        private List<TaskItemView> _currentTaskList;
        private List<TaskItemView> _newTaskList;
        private double _width = 46;
        private DateTime _currentDate;
        private readonly double _uiWidth;
        private readonly double _minZoom;
        private TappedRoutedEventArgs _tappedRoutedEventArgs;
        private PointerRoutedEventArgs _pointerRoutedEventArgs;
        public static readonly DependencyProperty ZoomProperty =
        DependencyProperty.Register(
                                        "Zoom",
                                        typeof(Double),
                                        typeof(TimelineDayPage),
                                        new PropertyMetadata(0d, OnValueChanged)
                                    );
        IntToShortTimeConverter _intToTimeConverter = new IntToShortTimeConverter();
        public Double Zoom
        {
            get
            {
                return (Double)GetValue(ZoomProperty);
            }
            set
            {
                SetValue(ZoomProperty, value);
            }
        }
        public TimelineDayPage()
        {
            InitializeComponent();
            Messenger.Instance.Register<TaskItemView>(UpdateDescription);

            TaskRepository.Instance.Tasks.CollectionChanged += Tasks_CollectionChanged;
            TimeScrollViewer.Tapped += TimeScrollViewer_Tapped;
            _uiWidth = Window.Current.Bounds.Width / 1366 * 1216;
            _minZoom = Converto3LengthFloat((float)(_uiWidth / IMAGE_WIDTH));
            TimeScrollViewer.PointerWheelChanged += TimeScrollViewer_PointerWheelChanged;
            TimeScrollViewer.PointerPressed += TimeGrid_PointerPressed;
        }

        /// <summary>
        /// Populates the page with content passed during navigation.  Any saved state is also
        /// provided when recreating a page from a prior session.
        /// </summary>
        /// <param name="navigationParameter">The parameter value passed to
        /// <see cref="Frame.Navigate(Type, Object)"/> when this page was initially requested.
        /// </param>
        /// <param name="pageState">A dictionary of state preserved by this page during an earlier
        /// session.  This will be null the first time a page is visited.</param>
        protected override void LoadState(Object navigationParameter, Dictionary<String, Object> pageState)
        {
            if (navigationParameter != null)
            {
                _currentDate = ((DateTime)navigationParameter);

                pageTitle.Text = _currentDate.ToString("dddd") + " " + _currentDate.ToString(CultureInfo.CurrentCulture.DateTimeFormat.ShortDatePattern);
            }
            BindWeatherBackground(_currentDate);
        }

        private void TimeGrid_PointerPressed(object sender, PointerRoutedEventArgs e)
        {
            if (e.Pointer.PointerDeviceType == PointerDeviceType.Touch)
            {
                TimeScrollViewer.ZoomMode = ZoomMode.Enabled;
            }
        }

        private void TimeScrollViewer_PointerWheelChanged(object sender, PointerRoutedEventArgs e)
        {
            _pointerRoutedEventArgs = e;
            _tappedRoutedEventArgs = null;

            if (e.KeyModifiers != VirtualKeyModifiers.Control)
            {
                return;
            }

            if (Math.Abs(TimeScrollViewer.ZoomFactor - 1) < EPSILON &&
                e.GetCurrentPoint(this).Properties.MouseWheelDelta == -120)
            {
                TimeScrollViewer.HorizontalScrollMode = ScrollMode.Disabled;
                Zoomming(1d, _minZoom);
            }

            if (
                !(Math.Abs(TimeScrollViewer.ZoomFactor - Converto3LengthFloat((float)(_uiWidth / IMAGE_WIDTH))) < EPSILON) ||
                e.GetCurrentPoint(this).Properties.MouseWheelDelta != 120) return;
            Zoomming(_minZoom, 1d);
            TimeScrollViewer.HorizontalScrollMode = ScrollMode.Enabled;
        }

        private void Zoomming(double from, double to)
        {
            TimeScrollViewer.HorizontalScrollMode = ScrollMode.Disabled;
            var sb = new Storyboard();
            var da = new DoubleAnimation
                                     {
                                         From = from,
                                         To = to,
                                         Duration = TimeSpan.FromSeconds(1d),
                                         EnableDependentAnimation = true
                                     };

            sb.Children.Add(da);
            Storyboard.SetTargetProperty(da, "Zoom");
            Storyboard.SetTarget(sb, this);
            sb.Begin();
        }

        private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var target = d as TimelineDayPage;
            var oldValue = (Double)e.OldValue;
            var newValue = (Double)e.NewValue;
            if (target == null) throw new NullReferenceException("target is null");
            target.OnValueChanged(oldValue, newValue);
        }

        // ReSharper disable UnusedParameter.Local
        private void OnValueChanged(Double oldValue, Double newValue)
        // ReSharper restore UnusedParameter.Local
        {
            // Zoom page step by step.
            TimeScrollViewer.ZoomToFactor((float)newValue);
            TimeScrollViewer.LayoutUpdated += TimeScrollViewerOnLayoutUpdated;
            TimeScrollViewer.UpdateLayout();
        }

        private void TimeScrollViewerOnLayoutUpdated(object sender, object o)
        {
            if (TimeScrollViewer.ScrollableWidth > 0)
            {
                double ratio = 1;
                if (_tappedRoutedEventArgs != null)
                {
                    ratio = _uiWidth / (_tappedRoutedEventArgs.GetPosition(this).X - (Window.Current.Bounds.Width / 1366 * 66));
                }

                if (_pointerRoutedEventArgs != null)
                {
                    var x = _pointerRoutedEventArgs.GetCurrentPoint(this).Position.X;
                    ratio = _uiWidth / (x - (Window.Current.Bounds.Width / 1366 * 66));
                }

                TimeScrollViewer.ScrollToHorizontalOffset(TimeScrollViewer.ScrollableWidth / ratio);
            }

            TimeScrollViewer.LayoutUpdated -= TimeScrollViewerOnLayoutUpdated;
        }

        private void TimeScrollViewer_Tapped(object sender, TappedRoutedEventArgs e)
        {
            _tappedRoutedEventArgs = e;
            _pointerRoutedEventArgs = null;
            if (Math.Abs(TimeScrollViewer.ZoomFactor - 1) > EPSILON)
            {
                Zoomming(_minZoom, 1d);
                TimeScrollViewer.HorizontalScrollMode = ScrollMode.Enabled;
            }

            TimeScrollViewer.ZoomMode = ZoomMode.Disabled;
        }

        private float Converto3LengthFloat(float input)
        {
            float outPut;
            outPut = input < 1 ? (float)Convert.ToDouble(input.ToString("f2")) : input;

            outPut -= (float)0.01;
            return outPut;
        }

        private void Tasks_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            // e.NewItems = item moi add. Cast ve item model
            if (e.NewItems != null && e.NewItems.Count > 0)
            {
                if (_newTaskList == null)
                {
                    _newTaskList = new List<TaskItemView>();
                }

                var taskModel = (TaskModel)e.NewItems[0];

                if (taskModel.UserID != GlobalData.MyUserID)
                {
                    return;
                }

                switch (taskModel.RepeatType)
                {
                    case 0:
                        if (Convert.ToDateTime(taskModel.StartDate).Day == _currentDate.Day
                       && Convert.ToDateTime(taskModel.StartDate).Month == _currentDate.Month
                       && Convert.ToDateTime(taskModel.StartDate).Year == _currentDate.Year)
                        {
                            _newTaskList.Add(new TaskItemView(taskModel));
                        }
                        break;

                    //daily
                    case 1:
                        _newTaskList.Add(new TaskItemView(taskModel));
                        break;

                    //weekly
                    case 2:
                        if (_currentDate.DayOfWeek == Convert.ToDateTime(taskModel.StartDate).DayOfWeek)
                        {
                            _newTaskList.Add(new TaskItemView(taskModel));
                        }
                        break;

                    // monthly
                    case 3:
                        if (_currentDate.Day == Convert.ToDateTime(taskModel.StartDate).Day)
                        {
                            _newTaskList.Add(new TaskItemView(taskModel));
                        }
                        break;

                    // yearly
                    case 4:
                        if (_currentDate.Day == Convert.ToDateTime(taskModel.StartDate).Day && _currentDate.Month == Convert.ToDateTime(taskModel.StartDate).Month)
                        {
                            _newTaskList.Add(new TaskItemView(taskModel));
                        }
                        break;
                }
            }

            if (e.OldItems != null && e.OldItems.Count > 0)
            {
                foreach (var item in e.OldItems)
                {
                    if (_currentTaskList != null)
                    {
                        var view = _currentTaskList.FirstOrDefault(p => p.DataModel.ID == ((TaskModel)item).ID);
                        if (view != null)
                        {
                            _currentTaskList.Remove(view);
                            TimeGrid.Children.Remove(view);
                        }
                    }
                }
            }

            UpdateTimeline();
        }

        private void UpdateTimeline()
        {
            try
            {
                foreach (var task in _newTaskList)
                {
                    task.Margin = new Thickness(GetLocationBaseTime(task.DataModel.StartTime) + 30, 0, 0, 0);
                    task.Width = _width;
                    task.HorizontalAlignment = HorizontalAlignment.Left;
                    task.VerticalAlignment = VerticalAlignment.Bottom;
                    task.SetValue(Grid.RowProperty, 0);
                    task.SetValue(Grid.RowSpanProperty, 2);
                    task.Height = GetItemHeight(task.DataModel.Priority);
                    task.Transitions = new TransitionCollection { new AddDeleteThemeTransition() };
                    if (_currentTaskList == null)
                    {
                        _currentTaskList = new List<TaskItemView>();
                    }

                    if (_currentTaskList.Contains(task)) continue;
                    _currentTaskList.Add(task);
                    TimeGrid.Children.Add(task);
                }

                _newTaskList.Clear();
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.StackTrace);
            }
        }

        private void UpdateDescription(object taskItem)
        {
            var task = taskItem as TaskItemView;
            if (task == null) return;
            TaskDetail.Text = task.DataModel.Description + string.Empty;
            TaskTitle.Text = task.DataModel.Name + string.Empty;
            // ReSharper disable AssignNullToNotNullAttribute
            TaskStart.Text = _intToTimeConverter.Convert(task.DataModel.StartTime, null, null, null) + " " + Convert.ToDateTime(task.DataModel.StartDate).ToString(CultureInfo.CurrentCulture.DateTimeFormat.ShortDatePattern);
            TaskEnd.Text = _intToTimeConverter.Convert(task.DataModel.EndTime, null, null, null) + " " + Convert.ToDateTime(task.DataModel.EndDate).ToString(CultureInfo.CurrentCulture.DateTimeFormat.ShortDatePattern);
            // ReSharper restore AssignNullToNotNullAttribute
        }

        private double GetItemHeight(int dPriority)
        {
            switch (dPriority)
            {
                case 2:
                    return 240;
                case 1:
                    return 210;
                case 0:
                    return 180;
            }

            return 195;
        }

        private int GetLocationBaseTime(int? dTimeO)
        {
            var oneH = (TimeGrid.ActualWidth - 60) / 24;
            var location = (dTimeO) * oneH / 60 - _width / 2;
            if (location == null) throw new ArgumentException("location is null");
            return (int)location;
        }

        private async void BindWeatherBackground(DateTime dt)
        {
            var imagePath = "../Assets/WeatherBackground/";
            var weather = await WeatherRepository.Instance.GetWeather(dt);
            if (weather == null)
            {
                imagePath += "unavailable.jpg";
            }
            else
            {
                switch (weather.WeatherType)
                {
                    case WeatherType.Barelycloudy:
                    case WeatherType.Morecloudy:
                        imagePath += "sunny.jpg";
                        break;
                    case WeatherType.Mostcloudy:
                    case WeatherType.Morecloudyday:
                        imagePath += "cloud.jpg";
                        break;
                    case WeatherType.Hail:
                        imagePath += "hail.jpg";
                        break;
                    case WeatherType.Lightrain:
                    case WeatherType.Heavyrain:
                        imagePath += "rain.jpg";
                        break;
                    case WeatherType.Heavysnow:
                    case WeatherType.Lightsnow:
                        imagePath += "snow.jpg";
                        break;
                    case WeatherType.Storm:
                        imagePath += "storm.jpg";
                        break;
                    case WeatherType.Sunny:
                        imagePath += "sunny.jpg";
                        break;
                    case WeatherType.Windy:
                        imagePath += "windy.jpg";
                        break;
                    default:
                        imagePath += "unavailable.jpg";
                        break;
                }
            }
            WeatherBackground.Source = new BitmapImage(new Uri(BaseUri, imagePath));
        }

        private async void BindingData(DateTime dt)
        {
            _newTaskList = new List<TaskItemView>();
            var listModels = await TaskRepository.Instance.GetTaskListFor(dt);
            foreach (var viewItem in listModels.Select(model => new TaskItemView(model)))
            {

                _newTaskList.Add(viewItem);
            }
            UpdateTimeline();
        }

        private void TimeGrid_Loaded(object sender, RoutedEventArgs e)
        {
            _width = (TimeGrid.ActualWidth - 60) / 60;
            BindingData(_currentDate);
            TimeScrollViewer.HorizontalScrollMode = ScrollMode.Disabled;
            TimeScrollViewer.ZoomToFactor(Converto3LengthFloat((float)(_uiWidth / IMAGE_WIDTH)));
            TimeScrollViewer.MaxZoomFactor = 1;
            TimeScrollViewer.MinZoomFactor = Converto3LengthFloat((float)(_uiWidth / IMAGE_WIDTH));
        }
    }
}